package cn.linstudy.service.impl;

import cn.linstudy.common.domain.UserInfo;
import cn.linstudy.common.exception.BusinessException;
import cn.linstudy.common.web.Result;
import cn.linstudy.domain.OrderInfo;
import cn.linstudy.domain.Product;
import cn.linstudy.domain.SeckillProduct;
import cn.linstudy.domain.SeckillProductVo;
import cn.linstudy.feign.ProductFeignApi;
import cn.linstudy.mapper.SeckillProductMapper;
import cn.linstudy.redis.SeckillRedisKey;
import cn.linstudy.service.IOrderInfoService;
import cn.linstudy.service.ISeckillProductService;
import cn.linstudy.util.IdGenerateUtil;
import cn.linstudy.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Slf4j
public class SeckillProductServiceImpl implements ISeckillProductService {
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    IOrderInfoService iOrderInfoService;
    @Autowired
    private ProductFeignApi productFeignApi;

    @Override
    public Result<List<SeckillProductVo>> querySeckillProductVOSByTime(int time) {
        // 先通过场次把秒杀商品查询出来
        List<SeckillProduct> seckillProducts = seckillProductMapper
            .queryCurrentlySeckillProduct(time);
        // 创建用于存储秒杀商品id的集合
        List<Long> ids = new ArrayList<>();

        for (SeckillProduct seckillProduct : seckillProducts) {
            ids.add(seckillProduct.getProductId());
        }
        // 远程调用商品服务，查询出商品数据
        Result<List<Product>> result = productFeignApi.queryByIds(ids);
        if (result != null && !result.hasError()){
            // 进行聚合操作
        List<Product> productList = result.getData();
        // 创建一个HashMap来存储
            HashMap<Long,Product> productHashMap = new HashMap<>();
            for (Product product : productList) {
                productHashMap.put(product.getId(),product);
            }
            // 创建一个List集合用于存储SeckillProductVo对象
            List<SeckillProductVo> seckillProductVos = new ArrayList<>();
           // 遍历seckillProducts集合
            for (SeckillProduct seckillProduct : seckillProducts) {
                // 先根据遍历秒杀商品集合得到每一个秒杀商品id查询出对应的商品
                Product product = productHashMap.get(seckillProduct.getProductId());
                // 新建一个seckillProductVo对象
                SeckillProductVo seckillProductVo = new SeckillProductVo();
                // 复制属性
                BeanUtils.copyProperties(product,seckillProductVo);
                // 复制属性，这个要第二个复制，因为要覆盖掉原来赋值的id，要显示出秒杀商品id
                BeanUtils.copyProperties(seckillProduct,seckillProductVo);
                seckillProductVos.add(seckillProductVo);
            }
        return Result.success(seckillProductVos);
        }
        return null;
    }

    @Override
    public Result<List<SeckillProductVo>> queryByTime(int time) {
        List<SeckillProductVo> vos = new ArrayList<>();
        // 根据时间去redis中去查询
        List<Object> values = redisTemplate.opsForHash()
            .values(SeckillRedisKey.SECKILL_PRODUCT_LIST.getRealKey(time + ""));
        for (Object value : values) {
            // 记得加引号
            vos.add(JSON.parseObject(value+"",SeckillProductVo.class));
        }
        return Result.success(vos);
    }

    @Override
    public Result<SeckillProductVo> find(int time, Long seckillId) {
        Object object = redisTemplate.opsForHash()
            .get(SeckillRedisKey.SECKILL_PRODUCT_LIST.getRealKey(time + ""), seckillId + "");
        if (object != null){
            return Result.success(JSON.parseObject(object+"",SeckillProductVo.class));
        }

        return null;
    }

    @Override
    @Transactional
    public String doSeckill(Long seckillId, int time, Long phone) {
        // 减少真实库存
        int stock = seckillProductMapper.decrStock(seckillId);
        if (stock == 0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        // 创建订单保存到数据库中
       String orderNo = createOrder(seckillId,time,phone);
        // 在redis中添加
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time+""),phone+":"+ seckillId);
        return orderNo;
    }

    @Override
    public void syncRedisStock(Integer time, Long seckillId) {
        // 查询MySQL真实库存
        int stockCount = seckillProductMapper.getStockCount(seckillId);
        // 放入Redis
        redisTemplate.opsForHash().put(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(time+""),seckillId+"",stockCount+"");
        log.info("回补预库存成功");
    }

    private String createOrder(Long seckillId, int time, Long phone) {
        SeckillProductVo seckillProductVo = seckillProductService
            .find(time, seckillId).getData();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCreateDate(new Date());
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId()+"");
        orderInfo.setUserId(phone);
        orderInfo.setProductId(seckillProductVo.getProductId());
        orderInfo.setProductName(seckillProductVo.getProductName());
        orderInfo.setProductImg(seckillProductVo.getProductImg());
        orderInfo.setProductCount(seckillProductVo.getStockCount());
        orderInfo.setProductPrice(seckillProductVo.getProductPrice());
        orderInfo.setSeckillPrice(seckillProductVo.getSeckillPrice());
        orderInfo.setSeckillDate(seckillProductVo.getStartDate());
        orderInfo.setSeckillTime(time);
        orderInfo.setSeckillId(seckillId);
        iOrderInfoService.insert(orderInfo);
        return orderInfo.getOrderNo();
    }
}
